package com.prs.crm.flow.adapter.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.courser.exception.IlegalException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.prs.crm.context.Constrains;
import com.prs.crm.domain.flow.WorkFlowExtra;
import com.prs.crm.domain.flow.WorkFlowNode;
import com.prs.crm.domain.flow.WorkFlowTransition;
import com.prs.crm.exception.InValidException;
import com.prs.crm.flow.FlowSorter;
import com.prs.crm.flow.adapter.IFlowXmlReader;

public class FlowXmlReaderImpl implements IFlowXmlReader  {
	
	private static final Logger log = Logger.getLogger(FlowXmlReaderImpl.class);
	
	private Map<String,WorkFlowNode> nodemap = new HashMap<String,WorkFlowNode>();
	private Map<String,WorkFlowTransition> nodetrans = new HashMap<String,WorkFlowTransition>();
	
	@SuppressWarnings("unchecked")
	public void read(String xml)  
	{
		try
		{
			nodemap.clear();
			nodetrans.clear();
			Document doc = DocumentHelper.parseText(xml);
			
			//get WorkflowProcess Element
			Element element = doc.getRootElement();
			//get node define
			Element ne = (Element) element.selectSingleNode("Activities");
			readFlowNode(ne.elements());
			//get node transition
			Element te = (Element)element.selectSingleNode("Transitions");
			readFlowtransition(te.elements());
			
			FlowSorter sorter = new FlowSorter(nodetrans.values(),nodemap.values());
			sorter.sort();
			
			
		}
		catch (InValidException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			log.error(e);
			throw new IlegalException(e);
		}
	}
	
	//获取结点信息
	private void readFlowNode(List<Element> nes)
	{
		int index=0;
		String nodetype = null;
		for (Element node :nes)
		{
			//   <Activitie id="11" type="END_NODE" name="结束" xCoordinate="380" yCoordinate="270" width="80" height="30"></Activitie>
			WorkFlowNode fnode = new WorkFlowNode();
			fnode.setId(Integer.parseInt(node.attributeValue("id")));
			fnode.setSequence(index++);
			nodetype = node.attributeValue("type");
			if (nodetype.equals("START_NODE"))
				fnode.setType(Constrains.WORKFLOW_STARTNODE);
			else if (nodetype.equals("NODE"))
				fnode.setType(Constrains.WORKFLOW_NODE);
			else if (nodetype.equals("FORK_NODE"))
				fnode.setType(Constrains.WORKFLOW_FORKNODE);
			else if (nodetype.equals("JOIN_NODE"))
				fnode.setType(Constrains.WORKFLOW_JOINNODE);
			else if (nodetype.equals("END_NODE"))
				fnode.setType(Constrains.WORKFLOW_ENDNODE);
			fnode.setName(node.attributeValue("name"));
			WorkFlowExtra extra = new WorkFlowExtra();
			extra.setXcoordinate(Float.parseFloat(node.attributeValue("xCoordinate")));
			extra.setYcoordinate(Float.parseFloat(node.attributeValue("yCoordinate")));
			extra.setWidth(Integer.parseInt(node.attributeValue("width")));
			extra.setHeight(Integer.parseInt(node.attributeValue("height")));
			fnode.setExtra(extra);
			extra.setNode(fnode);
			nodemap.put(fnode.getId().toString(), fnode);
		}
	}
	
	private void readFlowtransition(List<Element> tes)
	{
		// <Transition id="12" name="连接" from="1" to="2"></Transition>
		for (Element node : tes)
		{
			WorkFlowTransition trans = new WorkFlowTransition();
			trans.setId(Integer.parseInt(node.attributeValue("id")));
			trans.setName(node.attributeValue("name"));
			trans.setStartnode(getNode(node.attributeValue("from")));
			trans.setEndnode(getNode(node.attributeValue("to")));
			nodetrans.put(trans.getId().toString(), trans);
		}
	}
	
	private WorkFlowNode getNode(String id)
	{
		if (nodemap.containsKey(id))
			return nodemap.get(id);
		return null;
	}
	
	public Collection<WorkFlowNode> getNodes()
	{
		List<WorkFlowNode> nodeList = new ArrayList<WorkFlowNode>();
		nodeList.addAll(nodemap.values());
		Collections.sort(nodeList, new Comparator<WorkFlowNode>() {

			  public int compare(WorkFlowNode n1, WorkFlowNode n2) {
				  	if (n1.getType()==Constrains.WORKFLOW_STARTNODE
				  			|| n2.getType()==Constrains.WORKFLOW_ENDNODE)
				  		return -1;
				  	if (n1.getType()==Constrains.WORKFLOW_ENDNODE
				  			|| n2.getType()==Constrains.WORKFLOW_STARTNODE)
				  		return 1;
				  	return n1.getId()-n2.getId();
				  
			  }});
	
		return nodeList;
	}
	
	public Collection<WorkFlowTransition> getTransitions()
	{
		return nodetrans.values();
	}
}
